﻿using System;
using Microsoft.AspNetCore.Mvc;
using System.Text;
using System.Threading.Tasks;
using CoreCms.Net.Configuration;
using CoreCms.Net.Caching.AccressToken;
using CoreCms.Net.IServices;
using CoreCms.Net.Loging;
using CoreCms.Net.Model.Entities;
using CoreCms.Net.WeChat.Service.HttpClients;
using CoreCms.Net.WeChat.Service.Enums;
using CoreCms.Net.WeChat.Service.Models;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using SKIT.FlurlHttpClient.Wechat.Api.Models;
using SKIT.FlurlHttpClient.Wechat.Api;
using LogLevel = NLog.LogLevel;

namespace CoreCms.Net.Web.Controllers.WeChat
{
    /// <summary>
    /// 微信公众号用户授权事件
    /// </summary>
    public class WeChatOffiaccountOAuth2Controller : ControllerBase
    {
        //private readonly string _weChatAppId = AppSettingsConstVars.WeiXinAppId;
        //private readonly string _weChatSecret = AppSettingsConstVars.WeiXinAppSecret;
        //private readonly string _weChatOAuth2CallBackUrl = AppSettingsConstVars.AppConfigAppInterFaceUrl + "/WeCharOAuth2/UserInfoCallback";

        private readonly IWeChatApiHttpClientFactory _weChatApiHttpClientFactory;
        private readonly IWeChatUserAccessTokenServices _weChatUserAccessTokenServices;
        private readonly ICoreCmsUserWeChatInfoServices _weChatUserInfoServices;

        /// <summary>
        /// 构造函数
        /// </summary>
        public WeChatOffiaccountOAuth2Controller(IWeChatApiHttpClientFactory weChatApiHttpClientFactory, IWeChatUserAccessTokenServices weChatUserAccessTokenServices, ICoreCmsUserWeChatInfoServices weChatUserInfoServices)
        {
            _weChatApiHttpClientFactory = weChatApiHttpClientFactory;
            _weChatUserAccessTokenServices = weChatUserAccessTokenServices;
            _weChatUserInfoServices = weChatUserInfoServices;
        }

        /// <summary>
        /// OAuthScope.snsapi_userinfo方式回调
        /// </summary>
        /// <param name="code"></param>
        /// <param name="state"></param>
        /// <param name="bkUrl"></param>
        /// <returns></returns>
        [HttpGet]
        public async Task<ActionResult> UserInfoCallback(string code, string state, string bkUrl)
        {
            if (string.IsNullOrEmpty(code))
            {
                return Content("您拒绝了授权！");
            }

            //if (!state.Contains(","))
            //{
            //    //这里的state其实是会暴露给客户端的，验证能力很弱，这里只是演示一下
            //    //实际上可以存任何想传递的数据，比如用户ID，并且需要结合例如下面的Session["OAuthAccessToken"]进行验证
            //    return Content("验证失败！请从正规途径进入！");
            //}

            var client = _weChatApiHttpClientFactory.CreateWeXinClient();
            var accessToken = WeChatCacheAccessTokenHelper.GetWeChatAccessToken();

            var request = new SnsOAuth2AccessTokenRequest()
            {
                AccessToken = accessToken,
                Code = code
            };

            var response = await client.ExecuteSnsOAuth2AccessTokenAsync(request, HttpContext.RequestAborted);
            if (response.ErrorCode != (int)WeChatReturnCode.ReturnCode.请求成功)
            {
                return Content("错误：" + response.ErrorMessage);
            }

            NLogUtil.WriteFileLog(LogLevel.Info, LogType.WeChat, "获取用户accessToken", JsonConvert.SerializeObject(response));

            var accessTokenModel = await _weChatUserAccessTokenServices.QueryByClauseAsync(p => p.openid == response.OpenId);
            if (accessTokenModel == null)
            {
                accessTokenModel = new WeChatUserAccessToken();
                accessTokenModel.access_token = response.AccessToken;
                accessTokenModel.expires_in = response.ExpiresIn;
                accessTokenModel.openid = response.OpenId;
                accessTokenModel.refresh_token = response.RefreshToken;
                accessTokenModel.scope = response.Scope;
                accessTokenModel.unionid = response.UnionId;
                accessTokenModel.refresh_DateTime = DateTime.Now.AddSeconds(response.ExpiresIn);
                await _weChatUserAccessTokenServices.InsertAsync(accessTokenModel);
            }
            else
            {
                accessTokenModel.access_token = response.AccessToken;
                accessTokenModel.expires_in = response.ExpiresIn;
                //accessTokenModel.openid = response.OpenId;
                accessTokenModel.refresh_token = response.RefreshToken;
                accessTokenModel.scope = response.Scope;
                accessTokenModel.unionid = response.UnionId;
                accessTokenModel.refresh_DateTime = DateTime.Now.AddSeconds(response.ExpiresIn);
                await _weChatUserAccessTokenServices.UpdateAsync(accessTokenModel);
            }

            //因为第一步选择的是OAuthScope.snsapi_userinfo，这里可以进一步获取用户详细信息
            try
            {
                var userInfoRequest = new SnsUserInfoRequest()
                {
                    AccessToken = response.AccessToken,
                    OpenId = response.OpenId
                };

                var userInfoResponse = await client.ExecuteSnsUserInfoAsync(userInfoRequest, HttpContext.RequestAborted);
                if (userInfoResponse.ErrorCode == (int)WeChatReturnCode.ReturnCode.请求成功)
                {
                    var weChatUserInfo = await _weChatUserInfoServices.QueryByClauseAsync(p => p.openid == response.OpenId);
                    if (weChatUserInfo == null)
                    {
                        weChatUserInfo = new CoreCmsUserWeChatInfo()
                        {
                            createTime = DateTime.Now,
                            type = (int)GlobalEnumVars.UserAccountTypes.微信公众号,
                            //city = userInfoResponse.City,
                            //country = userInfoResponse.Country,
                            //province = userInfoResponse.Province,
                            nickName = userInfoResponse.Nickname,
                            //gender = userInfoResponse.Sex,
                            avatar = userInfoResponse.HeadImageUrl,
                            unionId = userInfoResponse.UnionId,
                            openid = userInfoResponse.OpenId,
                            gender = 1,
                            //isSubscribe = userInfoResponse.PrivilegeList,

                        };
                        var id = await _weChatUserInfoServices.InsertAsync(weChatUserInfo);
                        if (id > 0)
                        {
                            await _weChatUserInfoServices.UpdateAsync(
                                p => new CoreCmsUserWeChatInfo()
                                {
                                    userId = id
                                }, p => p.id == id);
                        }
                    }
                    else
                    {
                        if (weChatUserInfo.nickName != userInfoResponse.Nickname || weChatUserInfo.avatar != userInfoResponse.HeadImageUrl || weChatUserInfo.unionId != userInfoResponse.UnionId)
                        {
                            weChatUserInfo.nickName = userInfoResponse.Nickname;
                            weChatUserInfo.avatar = userInfoResponse.HeadImageUrl;
                            weChatUserInfo.unionId = userInfoResponse.UnionId;
                            await _weChatUserInfoServices.UpdateAsync(weChatUserInfo);
                        }
                    }
                }
                else
                {
                    return Content("错误：" + response.ErrorMessage);
                }

                var option = new CookieOptions
                {
                    Expires = DateTime.Now.AddSeconds(1440)
                };

                Response.Cookies.Append(GlobalConstVars.CookieOpenId, userInfoResponse.OpenId, option);

                if (!string.IsNullOrEmpty(bkUrl))
                {
                    var outBase64String = Convert.FromBase64String(bkUrl);
                    var orgStr = Encoding.Default.GetString(outBase64String);

                    return Redirect(orgStr);
                }
                else
                {
                    return Redirect(AppSettingsConstVars.AppConfigAppH5Url);
                }
            }
            catch (Exception ex)
            {
                return Content(ex.Message);
            }
        }

    }
}
